package hulppakket;

public class Camera {

	private Vector3f direction;
	private float fovy;
	private String name;
	private float near, far, right, left, bottom, top;
	private float nx, ny;
	private Point3f position;
	private Vector3f up;
	private Vector3f[] uvw;

	public Camera(Point3f position, Vector3f direction, Vector3f up,
			float fovy, String name) {
		this.position = position;
		this.direction = direction;
		this.up = up;
		this.fovy = fovy;
		this.name = name;
		nx = 512;
		ny = 512;
		createFieldOfView();
		this.uvw = getUVW();
	}

	private void createFieldOfView() {
		near = 1;
		far = Float.MAX_VALUE;
		top = (float) Math.tan(Math.toRadians((this.getFovy()) / 2.0));
		bottom = -top;
		right = -(nx / ny) * top;
		left = -right;
	}

	public float getFar() {
		return this.far;
	}

	public float getFovy() {
		return this.fovy;
	}

	public String getName() {
		return this.name;
	}

	public float getNear() {
		return this.near;
	}

	public float getNx() {
		return this.nx;
	}

	public float getNy() {
		return this.ny;
	}

	public Point3f getPosition() {
		return this.position;
	}

	public Ray getRay(float i, float j) {
		float us = (float) (left + ((right - left) * (i + 0.5f) * (1f / nx)));
		float vs = (float) (bottom + ((top - bottom) * (j + 0.5f) * (1f / ny)));
		float ws = near;
		Point3f origin = new Point3f(position);
		Vector3f directionTemp = new Vector3f(origin);
		directionTemp = directionTemp.add(uvw[0].scale(us));
		directionTemp = directionTemp.add(uvw[1].scale(vs));
		directionTemp = directionTemp.add(uvw[2].scale(ws));
		Vector3f direction = new Vector3f(origin);
		direction = direction.substract(directionTemp);
		direction = direction.normalize();
		return new Ray(origin, direction);
	}

	private Vector3f[] getUVW() {
		Vector3f[] result = new Vector3f[3];
		float x, y, z, normal;

		// calculating w
		normal = this.direction.length();
		x = (this.direction.x * (-1)) / normal;
		y = (this.direction.y * (-1)) / normal;
		z = (this.direction.z * (-1)) / normal;
		result[2] = new Vector3f(x, y, z);

		// calculating u
		Vector3f temp = this.up.crossProduct(result[2]);
		normal = temp.length();
		x = temp.x / normal;
		y = temp.y / normal;
		z = temp.z / normal;
		result[0] = new Vector3f(x, y, z);

		// calculating v
		result[1] = result[2].crossProduct(result[0]);

		return result;
	}
}
